/**
 * @file        eed.c
 * @brief       XXXX
 * @note        XXXX
 * @author      靳普诏(puzhao.jin@hopechart.com)
 * @date        2024/11/03
 * @version     1.0

 * @par         修改日志
 * <table>
 * <tr><th>Date         <th>Version     <th>Author      <th> Description
 * <tr><td>2024/11/03   <td>1.0         <td>靳普诏       <td> 创建初始版本
 * @copyright 杭州鸿泉物联网技术股份有限公司
 */
 
#include "edb.h"

#define EDB_HANDLE(self)    TEdb *self=&g_eed_

// typedef struct TEdbTag TEdb;
// struct TEdbTag
// {
//     const TEdbCfg *cfg_;
//     UInt8 refcount_;

//     TEdbDidState *state_buff_addr_; // 数据状态缓存地址
//     UInt8 *value_buff_addr_; // 数据值缓存地址
//     UInt8 *value_buff_end_; // 缓存地址结束位置
// };

static TEdb g_eed_ = {0};


static Bool L_Lock(void)
{
    Bool result = False;
    EDB_HANDLE(self);
    TEdbCfgDoLock func = self->cfg_->DoLock;

    if (func != NULL)
    {
        result = func(self->cfg_->cb_user_param);
    }

    return result;
}

static void L_Unlock(void)
{
    EDB_HANDLE(self);
    TEdbCfgDoUnlock func = self->cfg_->DoUnlock;

    if (func != NULL)
    {
        func(self->cfg_->cb_user_param);
    }
}


static UInt32 L_GetTickCount(void)
{
    EDB_HANDLE(self);
    TEdbCfgDoGetTickCount func = self->cfg_->DoGetTickCount;

    return func == NULL ? 0 : func(self->cfg_->cb_user_param);
}

static void L_Sleep(UInt32 ms)
{
    EDB_HANDLE(self);
    TEdbCfgDoSleep func = self->cfg_->DoSleep;

    if (func != NULL)
    {
        func(self->cfg_->cb_user_param, ms);
    }
}


// open refcount
static Bool L_EdbRefCountInc(TEdb *eed)
{
    Bool result = False;
    Int32 refcount = g_eed_.refcount_;

    if (refcount < 0x7FFFFFFFu)
    {
        L_Lock();
        g_eed_.refcount_++;
        L_Unlock();
        result = True;
    }

    return result;
}

static Bool L_EdbRefCountDec(TEdb *eed)
{
    Bool result = False;
    Int32 refcount = g_eed_.refcount_;

    if (refcount > 0)
    {
        L_Lock();
        g_eed_.refcount_--;
        L_Unlock();
        result = True;
    }

    return result;
}

// 触发插件初始化
static void L_TEdbTriggerPlugInit(TEdb *self)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnExecCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnInit;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param);
    }
}

Int32 EdbInit(const TEdbCfg *cfg, void *ram_buff, Int32 ram_buff_size)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);

    if (cfg != NULL 
        && cfg->did_def_table_ptr != NULL && cfg->did_def_table_len > 0
        && ram_buff != NULL && ram_buff_size > 0)
    {
        Int32 need_buff_size = 0;
        TEdbDidDef *pos = NULL;

        result = kEdbErrCodeOK;

        for (Int32 i = 0 ; i < cfg->plug_list_len; i++)
        {
            pos = &cfg->did_def_table_ptr[i];
            
            if (pos->val_buff_offset < need_buff_size)
            {
                result = kEdbErrCodeDidCfgError;
                break;
            }

            need_buff_size += pos->dlen;
            if ((pos->dtype & kEdbDataTypeMem) != 0)
                need_buff_size += 1;
        }

        if (result == kEdbErrCodeOK)
        {
            Int32 state_mem_size = cfg->plug_list_len * sizeof(TEdbDidState);
            need_buff_size += state_mem_size;

            if (ram_buff_size >= need_buff_size)
            {
                UInt8 *ptr = ram_buff;

                self->cfg_ = cfg;
                self->refcount_ = 0;
                self->state_buff_addr_ = (TEdbDidState *)ptr;
                self->value_buff_addr_ = &ptr[state_mem_size];
                self->value_buff_end_ = &ptr[need_buff_size];
                L_TEdbTriggerPlugInit(self);
            }
            else
                result = kEdbErrCodeNoMem;
        } 
        
    }

    return result;
}


// 触发插件释放
static void L_TEdbTriggerPlugDone(TEdb *self)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnExecCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnDone;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param);
    }
}

void  EdbDone()
{
    EDB_HANDLE(self);

    while (self->refcount_ != 0)
    {
        // <2024-12-07> Jpz : 等待
        L_Sleep(100);
    }

    L_TEdbTriggerPlugDone(self);
}


// 触发插件打开
static void L_TEdbTriggerPlugOpen(TEdb *self)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnExecCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnOpen;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param);
    }
}

Int32 EdbOpen()
{
    EDB_HANDLE(self);
    Int32 result = kEdbErrCodeFail;

    if (self->refcount_ < 255)
    {
        result = kEdbErrCodeOK;
        if (self->refcount_ == 0)
            L_TEdbTriggerPlugOpen(self);

        L_EdbRefCountInc(self);
    }
    
    return result;  
}


// 触发插件关闭
static void L_TEdbTriggerPlugClose(TEdb *self)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnExecCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnClose;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param);
    }
}
void  EdbClose()
{
    EDB_HANDLE(self);

    if (self->refcount_ == 1)
        L_TEdbTriggerPlugClose(self);

    L_EdbRefCountDec(self);
}


// 触发插件运行一次
static void L_TEdbTriggerPlugRunOnce(TEdb *self)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnExecCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnRunOnce;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param);
    }
}
void  EdbRunOnce()
{
    EDB_HANDLE(self);
    L_TEdbTriggerPlugRunOnce(self);
}


// -----------------------------------------------------



static TEdbDidDef *L_EdbGetDidDef(UInt16 did, Int32 *did_index)
{
    EDB_HANDLE(self);
    TEdbDidDef *result = NULL;
    TEdbDidDef *did_def_table_pos = self->cfg_->did_def_table_ptr;
    TEdbDidDef *did_def_table_end = did_def_table_pos + self->cfg_->did_def_table_len;

    *did_index = -1;
    // <2024-12-07> Jpz todo : 优化查找算法
    for (; did_def_table_pos < did_def_table_end; did_def_table_pos++)
    {
        if (did_def_table_pos->did == did)
        {
            result = did_def_table_pos;
            *did_index = did_def_table_pos - self->cfg_->did_def_table_ptr;
            break;
        }
    }


    return result;
}

TEdbDidDef *EdbGetDidDef(UInt16 did, UInt8 *r_errcode)
{
    Int32 errcode = kEdbErrCodeParamInval;
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL)
        errcode = kEdbErrCodeOK;

    if (r_errcode != NULL)
        *r_errcode = errcode;

    return did_def;
}

static void L_SetDidValState(Int32 did_index, UInt32 mask, Bool is_set)
{
    EDB_HANDLE(self);
    TEdbDidState *state_ptr = &self->state_buff_addr_[did_index];

    Bool curr = (state_ptr->val_state & mask) != 0;

    if (curr != is_set)
    {
        if (is_set)
            state_ptr->val_state |= mask;
        else
            state_ptr->val_state &= ~mask;
    }
}

static Bool L_GetDidValState(Int32 did_index, UInt32 mask)
{
    EDB_HANDLE(self);
    TEdbDidState *state_ptr = &self->state_buff_addr_[did_index];

    return (state_ptr->val_state & mask) != 0;
}

static void L_SetDidChgTick(Int32 did_index)
{
    EDB_HANDLE(self);
    TEdbDidState *state_ptr = &self->state_buff_addr_[did_index];

    state_ptr->chg_tick = L_GetTickCount();
}


// 触发插件值变化通知
static void L_TEdbTriggerPlugValueChange(TEdb *self, UInt16 did)
{
    TEdbPlug *plug = self->cfg_->plug_list;
    TEdbPlug *plug_end = plug + self->cfg_->plug_list_len;
    TEdbPlugOnNotifyCallback func = NULL;
    void *user_param = NULL;

    for (; plug < plug_end; plug++)
    {
        func = plug->OnRunOnce;
        user_param = plug->user_param;

        if (func != NULL)
            func(self, user_param, did);
    }
}
// 设置固定长度内存数据
static Int32 L_SetDidFixLenBuffValue(TEdbDidDef *did_def, Int32 did_index, const void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;

    if (value != NULL && len == did_def->dlen)
    {
        EDB_HANDLE(self);
        UInt8 *p = &self->value_buff_addr_[did_def->val_buff_offset];
        
        if (memcmp(p, value, len) != 0)
        {
            L_Lock();
            memcpy(p, value, len);
            L_SetDidChgTick(did_def);
            L_SetDidValState(did_index, kEdbDataStateMaskValueValid, True);
            L_SetDidValState(did_index, kEdbDataStateMaskValueChg, True);
            L_Unlock();
            
            L_TEdbTriggerPlugValueChange(self, did_def->did);
        }
        else if (!L_GetDidValState(did_index, kEdbDataStateMaskValueValid))
        {
            L_Lock();
            L_SetDidChgTick(did_def);
            L_SetDidValState(did_index, kEdbDataStateMaskValueValid, True);
            L_SetDidValState(did_index, kEdbDataStateMaskValueChg, True);
            L_Unlock();

            L_TEdbTriggerPlugValueChange(self, did_def->did);
        }

        result = len;
    }

    return result;
}
// 获取固定长度内存数据
static Int32 L_GetDidFixLenBuffValue(TEdbDidDef *did_def, Int32 did_index, void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeNotWritten;

    if (L_GetDidValState(did_index, kEdbDataStateMaskValueValid))
    {
        EDB_HANDLE(self);
        UInt8 *p = &self->value_buff_addr_[did_def->val_buff_offset];

        len = did_def->dlen;
        if (value == NULL)
            result = len;
        else if (len == did_def->dlen)
        {
            memcpy(value, p, len);
            result = len;
        }
        else
            result = kEdbErrCodeParamInval;
    }
    
    return result;
}


Int32 EdbGetValueBytes(UInt16 did, void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeBytes)
    {
        result = L_GetDidFixLenBuffValue(did_def, did_index, value, did_def->dlen);
    }

    return result;
}



Int32 EdbSetValueBytes(UInt16 did, const void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeBytes)
    {
        result = L_SetDidFixLenBuffValue(did_def, did_index, value, len);
    }

    return result;
}

Int32 EdbGetValueU08(UInt16 did, UInt8 *value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU08)
    {
        result = L_GetDidFixLenBuffValue(did_def, did_index, value, sizeof(*value));
    }
    return result;
}

Int32 EdbSetValueU08(UInt16 did, UInt8 value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU08)
    {
        result = L_SetDidFixLenBuffValue(did_def, did_index, &value, sizeof(value));
    }

    return result;
}

Int32 EdbGetValueU16(UInt16 did, UInt16 *value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU16)
    {
        result = L_GetDidFixLenBuffValue(did_def, did_index, value, sizeof(*value));
    }
    return result;
}
Int32 EdbSetValueU16(UInt16 did, UInt16 value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU16)
    {
        result = L_SetDidFixLenBuffValue(did_def, did_index, &value, sizeof(value));
    }
    return result;
}

Int32 EdbGetValueU32(UInt16 did, UInt32 *value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU32)
    {
        result = L_GetDidFixLenBuffValue(did_def, did_index, value, sizeof(*value));
    }
    return result;
}
Int32 EdbSetValueU32(UInt16 did, UInt32 value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU32)
    {
        result = L_SetDidFixLenBuffValue(did_def, did_index, &value, sizeof(value));
    }
    return result;
}

Int32 EdbGetValueU64(UInt16 did, UInt64 *value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU64)
    {
        result = L_GetDidFixLenBuffValue(did_def, did_index, value, sizeof(*value));
    }
    return result;
}
Int32 EdbSetValueU64(UInt16 did, UInt64 value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeU64)
    {
        result = L_SetDidFixLenBuffValue(did_def, did_index, &value, sizeof(value));
    }
    return result;
}

////////////////////////

// 获取可变长度内存数据
static Int32 L_GetDidVarLenBuffValue(TEdbDidDef *did_def, Int32 did_index, void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeNotWritten;

    L_Lock();
    if (L_GetDidValState(did_index, kEdbDataStateMaskValueValid))
    {
        EDB_HANDLE(self);
        UInt8 *p = &self->value_buff_addr_[did_def->val_buff_offset];

        if (p >= self->value_buff_end_)
            result = kEdbErrCodeNoMem;
        else if (value == NULL)
            result = p[0];
        else if (len >= p[0])
        {
            len = p[0];
            memcpy(value, &p[1], len);
            result = len;
        }
        else
            result = kEdbErrCodeNotEnoughLen;
    }
    L_Unlock();
    
    return result;
}
// 设置可变长度内存数据
static Int32 L_SetDidVarLenValBuffValue(TEdbDidDef *did_def, Int32 did_index, const void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;

    if (value != NULL && len <= did_def->dlen)
    {
        EDB_HANDLE(self);
        UInt8 *p = &self->value_buff_addr_[did_def->val_buff_offset];
        
        if (p >= self->value_buff_end_)
            result = kEdbErrCodeNoMem;
        else if (p[0] == len && memcmp(&p[1], value, len) == 0)
        {
            result = len;
            if (!L_GetDidValState(did_index, kEdbDataStateMaskValueValid))
            {
                L_Lock();
                L_SetDidChgTick(did_def);
                L_SetDidValState(did_index, kEdbDataStateMaskValueValid, True);
                L_SetDidValState(did_index, kEdbDataStateMaskValueChg, True);
                L_Unlock();

                L_TEdbTriggerPlugValueChange(self, did_def->did);
            }
        }
        else if (len <= did_def->dlen)
        {
            L_Lock();
            memcpy(&p[1], value, len);
            p[0] = (UInt8)len;
            L_SetDidChgTick(did_def);
            L_SetDidValState(did_index, kEdbDataStateMaskValueValid, True);
            L_SetDidValState(did_index, kEdbDataStateMaskValueChg, True);
            L_Unlock();

            result = len;
            L_TEdbTriggerPlugValueChange(self, did_def->did);
        }
        else
            result = kEdbErrCodeNoMem;
    }

    return result;
}


Int32 EdbGetValueMem(UInt16 did, void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeMem)
    {
        result = L_GetDidVarLenBuffValue(did_def, did_index, value, did_def->dlen);
    }

    return result;
}

Int32 EdbSetValueMem(UInt16 did, const void *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeMem)
    {
        result = L_SetDidVarLenValBuffValue(did_def, did_index, value, len);
    }

    return result;
}

Int32 EdbGetValueStr(UInt16 did, char *value, UInt32 len)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeStr)
    {
        result = L_GetDidVarLenBuffValue(did_def, did_index, value, did_def->dlen);

        if (result >= 0 && result < len)
        {
            value[result] = '\0';
        }
    }

    return result;
}

Int32 EdbSetValueStr(UInt16 did, const char *value)
{
    Int32 result = kEdbErrCodeParamInval;
    EDB_HANDLE(self);
    Int32 did_index;
    TEdbDidDef *did_def = L_EdbGetDidDef(did, &did_index);

    if (did_def != NULL && did_def->dtype == kEdbDataTypeStr)
    {
        Int32 len = strnlen(value, 255);
        result = L_SetDidVarLenValBuffValue(did_def, did_index, value, len);
    }

    return result;
}


///< Generated on "2024-11-03 16:52:00" by the tool "gen_hq_file.py >> V20231119" 

